package service

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	kmssdk "github.com/alibabacloud-go/kms-20160120/v3/client"
	"github.com/aliyun/alibabacloud-kms-agent/internal/model"
	"net/http"
	"time"
)

const (
	QueryParamsSecretId     = "secretId"
	QueryParamsVersionId    = "versionId"
	QueryParamsVersion      = "version"
	QueryParamsVersionStage = "versionStage"
)

func (s *Server) handlePing(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	_, _ = fmt.Fprintln(w, "healthy")
}

func (s *Server) handleGetSecret(w http.ResponseWriter, r *http.Request) {
	params, err := getSecretParams(r, s.pathPrefix)
	if err != nil {
		s.loggerWrapper.Error("get secret params error:%v", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	ctx, cancel := context.WithTimeout(r.Context(), time.Second*10)
	defer cancel()

	secret, err := s.FetchSecret(ctx, params)
	if err != nil {
		var v *model.ErrorResponse
		if errors.As(err, &v) {
			http.Error(w, v.Error(), v.StatusCode)
		} else {
			http.Error(w, err.Error(), http.StatusFailedDependency)
		}
		return
	}

	payload, err := transResponseFormat(secret, s.responseType)
	if err != nil {
		s.loggerWrapper.Error("trans response format error:%v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	_, err = w.Write(payload)
	if err != nil {
		http.Error(w, "Failed to write data", http.StatusInternalServerError)
	}
}

func transResponseFormat(secret string, t model.ResponseType) (payload []byte, err error) {
	// alibaba cloud kms format
	if t == model.ResponseTypeForAliyunKMS {
		return []byte(secret), nil
	}

	var secretValue kmssdk.GetSecretValueResponseBody
	err = json.Unmarshal([]byte(secret), &secretValue)
	if err != nil {
		err = fmt.Errorf("unmarshal secret value error:%w", err)
		return
	}

	// aws format
	if t == model.ResponseTypeForAWSSecretManager {
		secretInfo := &model.SecretManagerResponse{
			Name:          *secretValue.SecretName,
			VersionId:     *secretValue.VersionId,
			SecretString:  *secretValue.SecretData,
			VersionStages: make([]string, 0),
			CreatedDate:   *secretValue.CreateTime,
		}
		if len(secretValue.VersionStages.VersionStage) > 0 {
			for _, v := range secretValue.VersionStages.VersionStage {
				secretInfo.VersionStages = append(secretInfo.VersionStages, *v)
			}
		}
		payload, err = json.MarshalIndent(secretInfo, "", "   ")
		if err != nil {
			err = fmt.Errorf("marshal secret info error:%w", err)
			return
		}
	}

	// vault kv format
	if t == model.ResponseTypeForVaultKvSecret {
		var data map[string]interface{}
		err = json.Unmarshal([]byte(*secretValue.SecretData), &data)
		if err != nil {
			err = errors.New("secret data not kv format")
			return
		}
		kvSecret := &model.KVSecret{
			Data: data,
			Metadata: &model.SecretMetadata{
				CreatedTime: *secretValue.CreateTime,
			},
		}

		kvV2SecretData := model.KvV2SecretData{
			Data: kvSecret,
		}

		payload, err = json.Marshal(kvV2SecretData)
		if err != nil {
			err = fmt.Errorf("marshal secret data error:%w", err)
			return
		}
	}

	return
}
